package com.estun.backroundManagementService.task;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.estun.backroundManagementService.config.factoryMes.ApiCaller;
import com.estun.backroundManagementService.config.properties.ApiInfoProperties;
import com.estun.backroundManagementService.config.properties.LineInfoProperties;
import com.estun.backroundManagementService.config.threadPool.AsyncTask;
import com.estun.backroundManagementService.domain.factoryMes.request.PassStationRequest;
import com.estun.backroundManagementService.domain.factoryMes.request.ProductInfoRequest.ProductInfoBody;
import com.estun.backroundManagementService.domain.factoryMes.request.ProductInfoRequest.ProductInfoData;
import com.estun.backroundManagementService.domain.factoryMes.request.base.BaseMesRequest;
import com.estun.backroundManagementService.domain.factoryMes.request.base.BaseMesResponse;
import com.estun.backroundManagementService.modules.position.service.DeviceService;
import com.estun.backroundManagementService.modules.process.service.ProcessDetailService;
import com.estun.backroundManagementService.modules.product.model.Product;
import com.estun.backroundManagementService.modules.product.model.ProductPassStation;
import com.estun.backroundManagementService.modules.product.model.ProductStationTime;
import com.estun.backroundManagementService.modules.product.model.ProductValue;
import com.estun.backroundManagementService.modules.product.model.res.ProductStationReturn;
import com.estun.backroundManagementService.modules.product.service.ProductPassStationService;
import com.estun.backroundManagementService.modules.product.service.ProductService;
import com.estun.backroundManagementService.modules.product.service.ProductStationTimeService;
import com.estun.backroundManagementService.modules.product.service.ProductValueService;
import com.estun.backroundManagementService.modules.workOrder.dto.WorkOrderEntity;
import com.estun.backroundManagementService.modules.workOrder.service.WorkOrderService;
import com.estun.backroundManagementService.utils.DateTimeUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;


@Slf4j
@Component
@AllArgsConstructor
@Profile("prd")
public class PushPassStationTask {

    private final ApiCaller apiCaller;
    private final LineInfoProperties lineInfoProperties;
    private final ApiInfoProperties apiInfoProperties;
    private final ProductStationTimeService productStationTimeService;
    private final DeviceService deviceService;
    private final ProductService productService;
    private final ProcessDetailService processDetailService;
    private final WorkOrderService workOrderService;
    private final ProductValueService productValueService;
    private final ProductPassStationService productPassStationService;
    private static final ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private AsyncTask asyncTask;

    /**
     * 推送 过站信息定时任务
     */
    @Scheduled(fixedRate = 120 * 1000)
    public synchronized void pushPassStation() {
        long beginTime = System.currentTimeMillis();
        log.info("【推送过站记录】开始任务,任务号:{}", beginTime);
        //获取待推送的站点数据 状态为待推送 且 已过站的数据（diff_second不为0，判断为已过站)
        List<ProductPassStation> toBePushList = productPassStationService.getListToBePushed();
        if (CollectionUtils.isEmpty(toBePushList)) {
            log.warn("【推送过站记录】本次没有数据待推送，结束任务,任务号:{}", beginTime);
            return;
        }
        int toBePushSize = toBePushList.size();
        log.info("【推送过站记录】本次任务数量:{},任务号:{}", toBePushSize, beginTime);
        int failNumber = 0;
        for (ProductPassStation productPassStation : toBePushList) {
            ProductStationReturn productStationReturn = buildPassStationData(productPassStation);
            PassStationRequest passStationRequest = null;
            if (productStationReturn != null) {
                passStationRequest = productStationReturn.getData();
            }
            if (passStationRequest == null) {
                log.info("【推送过站记录】构造过站数据为空,任务号:{}", beginTime);
                continue;
            }
            BaseMesRequest<PassStationRequest> mesRequest = new BaseMesRequest<>();
            mesRequest.setData(Collections.singletonList(passStationRequest));
            BaseMesResponse mesResponse = new BaseMesResponse();
            mesResponse.setSuccess(true);
            //本线产品才调用接口推送
            if (!"outer".equals(passStationRequest.getLineCode())) {
                if ("scheduleCodeInit".equals(passStationRequest.getScheduleCode())
                || "orderCodeInit".equals(passStationRequest.getOrderCode())){
                    log.warn("【推送过站记录】排程编码为初始化值，不推送过站信息，任务号:{}", beginTime);
                    continue;
                }
                try {
                    mesResponse = apiCaller.post(apiInfoProperties.getPassStation(), mesRequest, BaseMesResponse.class);
                } catch (Exception e) {
                    log.error("【推送过站记录】接口调用异常，记录失败,任务号:{}", beginTime);
                    mesResponse = new BaseMesResponse();
                    mesResponse.setSuccess(false);
                    mesResponse.setFail(true);
                }
            }
            ProductStationTime productStationTime = new ProductStationTime();
            productStationTime.setId(productPassStation.getProductStationTimeId());
            //更新推送状态
            if (mesResponse.isSuccess()) {
                productStationTime.setSubmitStatus(1);
                // todo 推送生产参数数据 （过站记录推送失败则不再推送过站参数数据）
                try {
                    ProductPassStation productStationTimeReturn = productStationReturn.getProductStationTime();
                    WorkOrderEntity workOrder = productStationReturn.getWorkOrder();
                    String snNumber = productStationReturn.getSnNumber();
                    asyncTask.pushProductInfo(productStationTimeReturn, workOrder, snNumber);
                } catch (Exception e) {
                    log.error("【推送过站参数】异常,产品Id:{},工位Id:{}", productPassStation.getProductId(),productPassStation.getPassStationId(),e);
                }
            } else {
                log.error("【推送过站记录】推送失败 工厂MES返回:{},任务号:{}", mesResponse, beginTime);
                productStationTime.setSubmitStatus(-1);
                failNumber++;
            }
            productStationTime.setSubmitNumber(productPassStation.getPassSubmitNumber() + 1);
            boolean b = productStationTimeService.updateById(productStationTime);
            if (!b) {
                log.error("【推送过站记录】更新失败，productStationTime：{}", JSON.toJSONString(productStationTime));
            }
//            if (failNumber > 10 && successNumber == 0) {
//                log.info("【推送过站记录】前十个过站信息全部失败，停止推送。");
//            }
        }
        log.info("【推送过站记录】任务结束,耗时:{}ms，本次任务数量：{},成功数量:{},失败数量:{},任务号:{}", System.currentTimeMillis() - beginTime, toBePushSize, toBePushSize - failNumber, failNumber, beginTime);
    }


    /**
     * 构造过站信息RequestBody
     *
     * @param productStationTime
     * @return
     */
    private ProductStationReturn buildPassStationData(ProductPassStation productStationTime) {
        String stationId = productStationTime.getPassStationId();
        // 获取工序编码Z
        String processCode = processDetailService.getProcessCodeByStationCode(stationId);
        // 获取sn编码
        Long productId = productStationTime.getProductId();
        Product product = productService.getById(productId);

        String snNumber = "";
        if (product == null) {
            log.error("【推送过站记录】产品表不存在 productId:{}", productId);
            return null;
        }
        PassStationRequest data = new PassStationRequest();

        //获取工单信息
        WorkOrderEntity workOrder = workOrderService.getByScheduleCode(product.getScheduleCode());
        //如果为上板
        if (product.getType() == 1) {
            if (workOrder == null) {
                workOrder = workOrderService.getInProcessSchedule();
                product.setProductWorkOrderId(workOrder.getOrderCode());
                product.setScheduleCode(workOrder.getScheduleCode());
                log.error("【推送过站记录】产品:{},排程:{}不存在，补充生产中排程:{}", productStationTime.getProductId(), product.getScheduleCode(), workOrder.getScheduleCode());
            }
            String productNo = product.getProductNo();
            if (StringUtils.isBlank(productNo)) {
                log.error("【推送过站记录】没有产品码 处理防止重复推送 productId:{}", productId);
                productStationTimeService.handleNoProductNoByProductId(productId, stationId);
                return null;
            }
            snNumber = productNo;
        }
        //如果为下板
        else if (product.getType() == 2) {
            if (workOrder == null) {
                workOrder = workOrderService.getInProcessXpcSchedule();
                product.setProductWorkOrderId(workOrder.getOrderCode());
                product.setScheduleCode(workOrder.getScheduleCode());
                log.error("【推送过站记录】产品:{},排程:{}不存在，补充生产中排程:{}", productStationTime.getProductId(), product.getScheduleCode(), workOrder.getScheduleCode());
            }
            String lowerCode = product.getLowerCode();
            // 设置sn编码
            if (StringUtils.isBlank(lowerCode)) {
                log.error("【推送过站记录】没有下游路板码 productId:{}", productId);
                return null;
            }
            snNumber = lowerCode;
        } else {
            log.error("【推送过站记录】非本线产品:{}", productId);
            data.setLineCode("outer");
            ProductStationReturn productStationReturn =new ProductStationReturn();
            productStationReturn.setData(data);
            productStationReturn.setProductStationTime(productStationTime);
            productStationReturn.setWorkOrder(workOrder);
            productStationReturn.setSnNumber(snNumber);
            return productStationReturn;
        }
        // 获取设备编码
        String deviceCode = deviceService.getDeviceCodeByStationId(stationId);
        data.setSnNumber(snNumber);
        // 设置产线编码
        data.setLineCode(lineInfoProperties.getLineCode());
        if (workOrder != null) {
            // 设置物料编码
            data.setMaterialCode(workOrder.getMaterialCode());
            // 设置物料名称
            data.setMaterialName(workOrder.getMaterialName());
            // 设置物料版本
            data.setMaterialVersion(workOrder.getMaterialVersion());
        } else {
            log.error("【推送过站记录】 产品排程 生产中排程 都不存在,scheduleCode{}", product.getScheduleCode());
        }
        // 设置工序编码
        data.setOperationCode(processCode);
        // 设置工单编码
        data.setOrderCode(product.getProductWorkOrderId());
        // 设置排程编码
        data.setScheduleCode(product.getScheduleCode());
        // 设置过站开始时间
        data.setPassBeginTime(DateTimeUtils.localDateTimeToTimestamp(productStationTime.getPassStartTime()));
        // 设置过站结束时间
        data.setPassEndTime(DateTimeUtils.localDateTimeToTimestamp(productStationTime.getPassEndTime()));
        // 设置过站状态
        data.setPassStatus("pass");
        // 设置工位编码
        data.setStationCode(stationId);
        // todo 设置机器编码 待比亚迪给出
        data.setMachineId(deviceCode);
        data.setIsProduct(
                (
                        "COP010".equals(data.getOperationCode()) || "OP040".equals(data.getOperationCode()) ||
                                "2COP010".equals(data.getOperationCode()) || "2OP040".equals(data.getOperationCode())
                )
                        ?
                        "0" : "1");
        // 设置工厂编码
        data.setFactoryCode(lineInfoProperties.getFactoryCode());
        ProductStationReturn productStationReturn =new ProductStationReturn();
        productStationReturn.setData(data);
        productStationReturn.setProductStationTime(productStationTime);
        productStationReturn.setWorkOrder(workOrder);
        productStationReturn.setSnNumber(snNumber);
        return productStationReturn;
    }
}
